home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 July: Mac OS SDK / Dev.CD Jul 99 SDK1.toast / Development Kits / Mac OS / OpenGL 1.0 SDK / Source / Examples / aux / backtrace / scene.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1999-05-18  |  25.2 KB  |  1,154 lines  |  [TEXT/CWIE]

  1. /*
  2. * (c) Copyright 1993, 1994, 1995, 1996 Silicon Graphics, Inc.
  3. * ALL RIGHTS RESERVED 
  4. * Permission to use, copy, modify, and distribute this software for 
  5. * any purpose and without fee is hereby granted, provided that the above
  6. * copyright notice appear in all copies and that both the copyright notice
  7. * and this permission notice appear in supporting documentation, and that 
  8. * the name of Silicon Graphics, Inc. not be used in advertising
  9. * or publicity pertaining to distribution of the software without specific,
  10. * written prior permission. 
  11. *
  12. * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
  13. * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
  14. * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
  15. * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
  16. * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
  17. * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
  18. * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
  19. * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
  20. * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
  21. * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
  22. * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
  23. * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
  24. * US Government Users Restricted Rights 
  25. * Use, duplication, or disclosure by the Government is subject to
  26. * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
  27. * (c)(1)(ii) of the Rights in Technical Data and Computer Software
  28. * clause at DFARS 252.227-7013 and/or in similar or successor
  29. * clauses in the FAR or the DOD or NASA FAR Supplement.
  30. * Unpublished-- rights reserved under the copyright laws of the
  31. * United States.  Contractor/manufacturer is Silicon Graphics,
  32. * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
  33. *
  34. * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
  35. */
  36. #include "glu.h"
  37. #include "agl.h"
  38. #include "tk.h"
  39.  
  40. #include <math.h>
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43.  
  44. /* XXX */
  45. #include <string.h>
  46.  
  47. /*
  48. extern "C" {
  49. #include <rgb.h>
  50. };
  51. */
  52.  
  53. #include "Unitdisk.h"
  54.  
  55. #include "scene.h"
  56.  
  57. const GLfloat I[16] = {
  58.     1, 0, 0, 0,
  59.     0, 1, 0, 0,
  60.     0, 0, 1, 0,
  61.     0, 0, 0, 1
  62. };
  63.  
  64. Color white;
  65. Color black;
  66.  
  67. #define M_PI  3.14159265359
  68.  
  69. const double M_2PI = 2.0 * M_PI;
  70. const float scene_fudge = .000001;
  71.  
  72. /* Lights are native to the xz plane and are rotated into position - 
  73. * shadows and refraction will not have to be changed if lights are 
  74. * just rotating about the z axis */
  75. light lights[] = {
  76.     {{1, 0, 0, 1}, {0, 0, 0, 0}, {1, 0, 0, 0}, 
  77.     {1, 0, 0, 0,  0, 1, 0, 0,   0, 0, 1, 0,   0, 0, 0, 1},
  78.     "Red", 1},
  79.     {{0, 1, 0, 1}, {0, 0, 0, 0}, {0, 1, 0, 0},
  80.     {1, 0, 0, 0,  0, 1, 0, 0,   0, 0, 1, 0,   0, 0, 0, 1},
  81.     "Green", 1},
  82.     {{0, 0, 1, 1}, {0, 0, 0, 0}, {0, 0, 1, 0},
  83.     {1, 0, 0, 0,  0, 1, 0, 0,   0, 0, 1, 0,   0, 0, 0, 1},
  84.     "Blue", 1}
  85. };
  86.  
  87. GLfloat light_init_position[nlights][4] = 
  88.     {{1.5, 0, 2.5, 1}, {1, 0, 3, 1}, {2, 0, 3, 1}};
  89. GLfloat light_init_rotation[nlights] = {135, 0, 90};
  90. GLfloat light_rotation[nlights];
  91.  
  92. Color world_ambient(.25, .25, .25);
  93.  
  94. GLfloat index = indices[def_refraction_index].index;
  95.  
  96. GLfloat square_ambient[4] = {.25, .25, .25, 1};
  97. GLfloat square_diffuse[4] = {1, 1, 1, 1};
  98. GLfloat square_specular[4] = {0, 0, 0, 1};
  99.  
  100. const GLfloat fov = 45.0;
  101. GLfloat aspect = 1.0;
  102. GLfloat eyep[3] = {-6, 0, 6};
  103. GLfloat lookp[3] = {0, 0, 1};
  104.  
  105.  
  106. /*
  107. static GLXContext glx_context;
  108. */
  109.  
  110. const int max_args = 20;
  111.  
  112. static int list_square;
  113. static int lists_shadows;
  114. static int lists_refraction;
  115. static int lists_lights = 5;
  116. static int list_sphere = 4;
  117. static int list_spheredisk = 9;
  118. static int list_lights_on = 6;
  119. static int list_lights_off = 7;
  120. static int list_light_draw = 8;
  121.  
  122. int draw_square = 1;
  123. int draw_shadows = 1;
  124. int draw_refraction = 1;
  125. int draw_sphere = 1;
  126. int draw_lights = 1;
  127. int draw_texture = 1;
  128.  
  129. int possible_divisions[] = {10, 20, 30, 40};
  130.  
  131. // Sphere is stored as floats - more efficient
  132. GLfloat *spherepts = NULL;
  133. int nspherepts = 0;
  134. int spherediv = 0;
  135. Point_b sphere_position = {0, 0, 1, 1};
  136. GLfloat sphere_size = .5;
  137. const GLfloat sphere_ambient[4] = {0, 0, 0, 0};
  138. const GLfloat sphere_specular[4] = {0, 0, 0, 0};
  139. Unitdisk sphere_disk;
  140. static void sphere_build();
  141. static void sphere_list_init();
  142. static void sphere_draw();
  143.  
  144. static void square_list_init();
  145.  
  146. static void lights_init_onoff();
  147. static void lights_init_position();
  148. static void lights_init_position(int i);
  149. static void lights_list_init2(void);
  150. static void lights_list_init(int n);
  151.  
  152. static void light_draw_list_init();
  153.  
  154. Unitdisk disks[nlights];
  155. int diskdiv = possible_divisions[def_divisions_index];
  156. static void disk_build();
  157. static void disk_build(int disk);
  158.  
  159.  
  160. Unitdisk shadows[nlights];
  161. static void shadow_list_init();
  162. static void shadow_list_init(int n);
  163. static void shadow_draw(int n);
  164.  
  165. Unitdisk refraction[nlights];
  166. static void refraction_list_init();
  167. static void refraction_list_init(int n);
  168.  
  169. static void shadow_refraction_full_build();
  170. static void shadow_refraction_full_build(int n);
  171.  
  172. void scene_init();
  173. static void lists_init();
  174. static void lights_init();
  175. static int lights_move(int light, float dr, float dphi, float dtheta, 
  176. int update);
  177. static void lights_move_update(int light, int dr, int dphi, int dtheta);
  178.  
  179. void scene_draw();
  180.  
  181. void texture_init();
  182.  
  183. TK_RGBImageRec *teximage = NULL;
  184.  
  185. inline float sign(float a) 
  186. {
  187.     // This is badly written so let's not call it too often, ok?
  188.     return (a > 0) ? 1 : (a < 0) ? -1 : 0;
  189. }
  190.  
  191. inline double degrees(double a)
  192. {
  193.     return (a * 180.0 / M_PI);
  194. }
  195.  
  196. inline double radians(double a)
  197. {
  198.     return (a * M_PI / 180.0);
  199. }
  200.  
  201. inline double degrees_clamp(double a)
  202. {
  203.     while (a < 0.0) a += 360.0;
  204.     while (a > 360.0) a -= 360.0;
  205.     return a;
  206. }
  207.  
  208. inline double radians_clamp(double a)
  209. {
  210.     while (a < 0.0) a += M_2PI;
  211.     while (a > M_2PI) a -= M_2PI;
  212.     return a;
  213. }
  214.  
  215. void scene_init()
  216. {
  217.     int i;
  218.  
  219.     white.c[0] = white.c[1] = white.c[2] = white.c[3] = 1;
  220.     black.c[0] = black.c[1] = black.c[2] = 0;
  221.     black.c[3] = 1;
  222.  
  223.     lists_init();
  224.  
  225.  
  226.     for (i = 0; i < nlights; i++) 
  227.     {
  228.         lights[i].pos = light_init_position[i];
  229.         light_rotation[i] = light_init_rotation[i];
  230.         lights_init_position(i);
  231.     }
  232.  
  233.     divisions_change(possible_divisions[def_divisions_index]);
  234.  
  235.     lights_init_onoff();
  236.     lights_init();
  237.     lights_init_position();
  238.  
  239.     texture_init();
  240.  
  241.     glClearStencil(0);
  242.  
  243.     // This is for profiling
  244.     // exit(0);
  245. }
  246.  
  247. static void scene_project()
  248. {
  249.     glMatrixMode(GL_PROJECTION);
  250.     //glLoadIdentity();
  251.     gluPerspective(fov, aspect, 0.01, 20.0);
  252.     //glMatrixMode(GL_MODELVIEW);
  253.     //glLoadIdentity();
  254.     gluLookAt(eyep[0], eyep[1], eyep[2], lookp[0], lookp[1], lookp[2], 1, 0, 0);
  255. }
  256.  
  257. static void scene_rasterize()
  258. {
  259.     int i;
  260.  
  261.     glLoadName(name_square);
  262.     
  263.     if (draw_square) 
  264.     {
  265.         if (draw_texture) glEnable(GL_TEXTURE_2D);
  266.         //glCallList(list_square);
  267.         square_list_init();
  268.         glDisable(GL_TEXTURE_2D);
  269.     }
  270.     
  271.     if (draw_shadows) 
  272.     {
  273.         for (i = 0; i < nlights; i++) 
  274.         {
  275.             if (lights[i].on) 
  276.             {
  277.                 glPushMatrix();
  278.                 glRotatef(-light_rotation[i], 0, 0, 1);
  279.                 glCallList(lists_shadows + i);
  280.                 glPopMatrix();
  281.             }
  282.         }
  283.     }
  284.     
  285.     if (draw_refraction)
  286.     {
  287.         for (i = 0; i < nlights; i++) 
  288.         {
  289.             if (lights[i].on) 
  290.             {
  291.                 glPushMatrix();
  292.                 glRotatef(-light_rotation[i], 0, 0, 1);
  293.                 glCallList(lists_refraction + i);
  294.                 glPopMatrix();
  295.             }
  296.         }
  297.     }
  298.  
  299.     glLoadName(name_sphere);
  300.     /* Drawing the sphere here makes the sphere visible through itself when we
  301.     * do the refraction redraw hack -- for now, just don't draw it */
  302.     //  if (draw_sphere) glCallList(list_sphere);
  303.  
  304.     for (i = 0; i < nlights; i++)
  305.     {
  306.         if (draw_lights) glCallList(lists_lights + i);
  307.     }
  308. }
  309.  
  310. /* This draws an image of the scene seen through the sphere */
  311. static void scene_draw_refracted()
  312. {
  313.     int i;
  314.  
  315.     if (!draw_sphere) return;
  316.  
  317.  
  318.     /* Draw an image of the sphere into the stencil plane  - 
  319.     * must do this every time in case the lights have moved in front
  320.     * of it */
  321.     glEnable(GL_STENCIL_TEST);
  322.     glClearStencil(0);
  323.     glClear(GL_STENCIL_BUFFER_BIT);
  324.     glStencilFunc(GL_ALWAYS, 0x1, 0x1);
  325.     glStencilOp(GL_REPLACE, GL_KEEP, GL_REPLACE);
  326.  
  327.     glColorMask(0, 0, 0, 0);
  328.  
  329.     glMatrixMode(GL_PROJECTION);
  330.     glLoadIdentity();
  331.     scene_project();
  332.  
  333.     glEnable(GL_DEPTH_TEST);
  334.     glEnable(GL_CULL_FACE);
  335.     glCallList(list_sphere);
  336.     glDisable(GL_CULL_FACE);
  337.     glDisable(GL_DEPTH_TEST);
  338.  
  339.     glColorMask(1, 1, 1, 1);
  340.  
  341.  
  342.     /* Set up a transform with a wider field of view  - this is inaccurate 
  343.     * but I don't have time to do it right */
  344.     glMatrixMode(GL_PROJECTION);
  345.     glLoadIdentity();
  346.     gluPerspective(fov * index, aspect, 0.01, 20.0);
  347.     gluLookAt(eyep[0], eyep[1], eyep[2], lookp[0], lookp[1], lookp[2], 1, 0, 0);
  348.     glMatrixMode(GL_MODELVIEW);
  349.     glLoadIdentity();
  350.  
  351.     /* Set up the stencil stuff which will be used to draw the image */
  352.     glStencilFunc(GL_NOTEQUAL, 0x0, 0xffffffff);
  353.     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  354.  
  355.     /* Draw the image, gambling that we'll never see anything but the
  356.     * floor through the table */
  357.     glLoadName(name_sphere);
  358.     
  359.     if (draw_texture) glEnable(GL_TEXTURE_2D);
  360.     //if (draw_square) glCallList(list_square);
  361.     square_list_init();
  362.     
  363.     if (draw_shadows)    
  364.     {
  365.         for (i = 0; i < nlights; i++)
  366.         {
  367.             if (lights[i].on) 
  368.             {
  369.                 glPushMatrix();
  370.                 glRotatef(-light_rotation[i], 0, 0, 1);
  371.                 glCallList(lists_shadows + i);
  372.                 glPopMatrix();
  373.             }
  374.         }
  375.     }
  376.     
  377.     if (draw_refraction)
  378.     {
  379.         for (i = 0; i < nlights; i++)
  380.         {
  381.             if (lights[i].on)
  382.             {
  383.                 glPushMatrix();
  384.                 glRotatef(-light_rotation[i], 0, 0, 1);
  385.                 glCallList(lists_refraction + i);
  386.                 glPopMatrix();
  387.             }
  388.         }
  389.     }
  390.     
  391.     glDisable(GL_TEXTURE_2D);
  392.  
  393.     /* Draw the sphere to make it look like it
  394.     * has some substance */
  395.     glMatrixMode(GL_PROJECTION);
  396.     glLoadIdentity();
  397.     scene_project();
  398.     glCallList(list_spheredisk);
  399.  
  400.     glDisable(GL_STENCIL_TEST);
  401. }
  402.  
  403.  
  404. void scene_draw() 
  405. {
  406.     glMatrixMode(GL_PROJECTION);
  407.     glLoadIdentity();
  408.  
  409.     glMatrixMode(GL_MODELVIEW);
  410.     glLoadIdentity();
  411.  
  412.     scene_project();
  413.  
  414.     /* Should draw an image of the square into the stencil buffer 
  415.     * to make sure that refractions which are not on the square do not get
  416.     * drawn, but it can wait. */
  417.  
  418.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  419.     scene_rasterize();
  420.  
  421.     scene_draw_refracted();
  422. }
  423.  
  424. const int pick_maxz = 0xffffffff;
  425.  
  426. int scene_pick(GLdouble x, GLdouble y)
  427. {
  428.     GLuint buffer[128];
  429.     GLint vp[4], nhits, nnames;
  430.     GLuint minz, hit = name_background;
  431.     GLint i, j;
  432.  
  433.     glMatrixMode(GL_MODELVIEW);
  434.     glLoadIdentity();
  435.  
  436.     glMatrixMode(GL_PROJECTION);
  437.     glLoadIdentity();
  438.  
  439.     glGetIntegerv(GL_VIEWPORT, vp);
  440.  
  441.     glSelectBuffer(128, buffer);
  442.     glRenderMode(GL_SELECT);
  443.  
  444.     // Where is this supposed to go, anyway?
  445.     gluPickMatrix(x, vp[3] - y, 1, 1, vp);
  446.  
  447.     scene_project();
  448.  
  449.     glMatrixMode(GL_MODELVIEW);
  450.  
  451.     glInitNames();
  452.     glPushName(name_background);
  453.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  454.     scene_rasterize();
  455.     glFlush();
  456.     nhits = glRenderMode(GL_RENDER);
  457.  
  458.     minz = pick_maxz;
  459.     for (i = j = 0; j < nhits; j++)
  460.     {
  461.         nnames = buffer[i];
  462.         i++;
  463.         if (buffer[i] < minz)
  464.         {
  465.             minz = buffer[i];
  466.             hit = buffer[i + 1 + nnames];
  467.         }
  468.     
  469.         i++;
  470.         i += nnames + 1;
  471.     }
  472.     
  473.     if (minz == pick_maxz) return name_background;
  474.     else return hit;
  475. }
  476.  
  477. void scene_reset_lights() 
  478. {
  479.     int i;
  480.     
  481.     for (i = 0; i < nlights; i++)
  482.     {
  483.         lights[i].pos = light_init_position[i];
  484.         light_rotation[i] = light_init_rotation[i];
  485.     }
  486.     
  487.     lights_init_position();
  488.     lights_list_init2();
  489. }
  490.  
  491. static void square_list_init()
  492. {
  493.     GLfloat x, y, inc;
  494.     int i, j;  
  495.     
  496.     //glNewList(list_square, GL_COMPILE);
  497.     //glLoadName(name_square);
  498.     
  499.     glNormal3f(0, 0, 1);
  500.     glEnable(GL_LIGHTING);
  501.     
  502.     glCallList(list_lights_on);
  503.     
  504.     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, square_ambient);
  505.     glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, square_diffuse);
  506.     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, square_specular);
  507.     
  508.     inc = 10.0 / diskdiv;
  509.     //glEnable(GL_CULL_FACE);
  510.  
  511.     for (i = 0, y = -5.0; i < diskdiv; i++, y += inc)
  512.     {
  513.         glBegin(GL_TRIANGLE_STRIP);
  514.         
  515.         for (j = 0, x = -5.0; j <= diskdiv; j++, x += inc)
  516.         {
  517.             glTexCoord2f(x, y + inc);
  518.             glVertex2f(x, y + inc);
  519.             glTexCoord2f(x, y);
  520.             glVertex2f(x, y);
  521.         }
  522.         
  523.         glEnd();
  524.     }
  525.  
  526.     glDisable(GL_CULL_FACE);
  527.     glCallList(list_lights_off);
  528.     glDisable(GL_LIGHTING);
  529.     //glEndList();
  530. }
  531.  
  532. static void spheredisk_list_init()
  533. {
  534.     glNewList(list_spheredisk, GL_COMPILE);
  535.     glEnable(GL_BLEND);
  536.     glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
  537.     glEnable(GL_LIGHTING);
  538.     glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
  539.     glEnable(GL_COLOR_MATERIAL);
  540.     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, sphere_ambient);
  541.     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, sphere_specular);
  542.     glCallList(list_lights_on);
  543.     sphere_disk.draw();
  544.     glCallList(list_lights_off);
  545.     glDisable(GL_COLOR_MATERIAL);
  546.     glDisable(GL_LIGHTING);
  547.     glDisable(GL_BLEND);
  548.     glEndList();
  549. }
  550.  
  551. void lights_onoff(int light, int val)
  552. {
  553.     lights[light].on = val;
  554.     lights_init_onoff();
  555.     lights_list_init(light);
  556.     square_list_init();
  557. }
  558.  
  559. void refraction_change(GLfloat refraction)
  560. {
  561.     if (refraction == index) return;
  562.     index = refraction;
  563.     shadow_refraction_full_build();
  564.     refraction_list_init();
  565. }
  566.  
  567. void divisions_change(int divisions)
  568. {
  569.     Point_b eye, look;
  570.  
  571.     if (divisions != spherediv)
  572.     {
  573.         spherediv = divisions;
  574.  
  575.         light_draw_list_init();
  576.         lights_list_init2();
  577.  
  578.         sphere_disk.set_divisions(spherediv, spherediv);
  579.         sphere_disk.fill_points();
  580.         sphere_disk.set_colors(white);
  581.         sphere_disk.scale_alpha_by_z();
  582.         eye = eyep;
  583.         look = lookp;
  584.         sphere_disk.face_direction((eye - look).unit());
  585.         sphere_disk.copy_normals_from_points();
  586.         sphere_disk.scale_translate(sphere_size, sphere_position);
  587.         sphere_build();
  588.         sphere_list_init();
  589.  
  590.         diskdiv = divisions;
  591.         disk_build();
  592.         shadow_refraction_full_build();
  593.         square_list_init();
  594.         spheredisk_list_init();
  595.         shadow_list_init();
  596.         refraction_list_init();
  597.     }
  598. }
  599.  
  600. int scene_move(int name, float dr, float dphi, float dtheta, int update)
  601. {
  602.     switch(name)
  603.     {
  604.         case name_background:
  605.             return 0;
  606.         case name_square:
  607.             return 0;
  608.         case name_sphere:
  609.             return 0;
  610.         default:
  611.             if (name < name_lights || name > name_lights + nlights) return 0;
  612.         return lights_move(name - name_lights, dr, dphi, dtheta, update);
  613.     }
  614. }
  615.  
  616. void scene_move_update(int name, int dr, int dphi, int dtheta)
  617. {
  618.     switch(name)
  619.     {
  620.         case name_background:
  621.             break;
  622.         case name_square:
  623.             break;
  624.         case name_sphere:
  625.             break;
  626.         default:
  627.             if (name < name_lights || name > name_lights + nlights) break;
  628.             lights_move_update(name - name_lights, dr, dphi, dtheta);
  629.             break;
  630.     }
  631. }
  632.  
  633.  
  634. static void lights_init_onoff()
  635. {
  636.     int i;
  637.  
  638.     glNewList(list_lights_on, GL_COMPILE);
  639.     
  640.     for (i = 0; i < nlights; i++)
  641.     {
  642.         if (lights[i].on) glEnable(GL_LIGHT0 + i);
  643.         else glDisable(GL_LIGHT0 + i);
  644.     }
  645.     
  646.     glEndList();
  647.  
  648.     glNewList(list_lights_off, GL_COMPILE);
  649.     
  650.     for (i = 0; i < nlights; i++) glDisable(GL_LIGHT0 + i);
  651.     {
  652.         glEndList();
  653.     }
  654. }
  655.  
  656.  
  657.  
  658. static void lights_init_position()
  659. {
  660.     int i;
  661.  
  662.     for (i = 0; i < nlights; i++) lights_init_position(i);
  663. }
  664.  
  665. static void lights_init_position(int i) 
  666. {
  667.     Point_b l, d;
  668.  
  669.     glMatrixMode(GL_MODELVIEW);
  670.     glLoadIdentity();
  671.     glMatrixMode(GL_PROJECTION);
  672.     glLoadIdentity();
  673.  
  674.     l = lights[i].pos;
  675.     l.pt[0] = lights[i].pos.pt[0] * cos(radians(light_rotation[i]));
  676.     l.pt[1] = lights[i].pos.pt[0] * -sin(radians(light_rotation[i]));
  677.     
  678.     d = (sphere_position - l).unit();
  679.     glLightfv(GL_LIGHT0 + i, GL_POSITION, l.pt);
  680.     glLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, d.pt);
  681. }
  682.  
  683. static void lights_list_init2(void)
  684. {
  685.     int i;
  686.     for (i = 0; i < nlights; i++) lights_list_init(i);
  687. }
  688.  
  689. static void lights_list_init(int n)
  690. {
  691.     Color c;
  692.  
  693.     glNewList(lists_lights + n, GL_COMPILE);
  694.     
  695.     if (lights[n].on)
  696.     {
  697.         glLoadName(name_lights + n);
  698.  
  699.         glEnable(GL_DEPTH_TEST);
  700.         glEnable(GL_LIGHTING);
  701.         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
  702.         glCallList(list_lights_on);
  703.  
  704.         c = lights[n].diffuse;
  705.         glMaterialfv(GL_BACK, GL_AMBIENT, c.c);
  706.         glMaterialfv(GL_BACK, GL_DIFFUSE, black.c);
  707.         glMaterialfv(GL_BACK, GL_SPECULAR, black.c);
  708.  
  709.         glMaterialfv(GL_FRONT, GL_AMBIENT, (c * .75).c);
  710.         glMaterialfv(GL_FRONT, GL_DIFFUSE, white.c);
  711.         glMaterialfv(GL_FRONT, GL_SPECULAR, white.c);
  712.  
  713.         glMatrixMode(GL_MODELVIEW);
  714.         glPushMatrix();
  715.         glRotatef(-light_rotation[n], 0, 0, 1);
  716.         glTranslatef(lights[n].pos.pt[0], lights[n].pos.pt[1], 
  717.         lights[n].pos.pt[2]);
  718.         glRotatef(-degrees(atan2(lights[n].pos.pt[2] - sphere_position.pt[2],
  719.         lights[n].pos.pt[0])), 0, 1, 0);
  720.         glCallList(list_light_draw);
  721.         glPopMatrix();
  722.  
  723.         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
  724.         glDisable(GL_LIGHTING);
  725.         glCallList(list_lights_off);
  726.         glDisable(GL_DEPTH_TEST);
  727.     }
  728.     else
  729.     {
  730.         /* 5.0.1 for Elans seems to object strongly to replacing
  731.         * empty display lists, so will put some stupid command
  732.         * in here */
  733.         glColor3f(0, 0, 0);
  734.     }
  735.     
  736.     glEndList();
  737. }
  738.  
  739. static void light_draw_list_init()
  740. {
  741.     float c, s;
  742.     int t;
  743.  
  744.     glNewList(list_light_draw, GL_COMPILE);
  745.     glEnable(GL_NORMALIZE);
  746.     glMatrixMode(GL_MODELVIEW);
  747.     glPushMatrix();
  748.     glScalef(.25, .15, .15);
  749.     glBegin(GL_QUAD_STRIP);
  750.     
  751.     for (t = 0; t <= spherediv; t++)
  752.     {
  753.         c = cos(M_2PI * (float)t / (float)spherediv);
  754.         s = sin(M_2PI * (float)t / (float)spherediv);
  755.         glNormal3f(.25, .968*s, .968*c);
  756.         glVertex3f(0, s, c);
  757.         glVertex3f(1, .75*s, .75*c);
  758.     }
  759.     
  760.     glEnd();
  761.     glNormal3f(1, 0, 0);
  762.     glBegin(GL_TRIANGLE_STRIP);
  763.     
  764.     for (t = 0; t <= spherediv; t++)
  765.     {
  766.         c = cos(M_2PI * (float)t / (float)spherediv);
  767.         s = sin(M_2PI * (float)t / (float)spherediv);
  768.         glVertex3f(1, .75*s, .75*c);
  769.         glVertex3f(1, 0, 0);
  770.     }
  771.     
  772.     glEnd();
  773.     glPopMatrix();
  774.     glDisable(GL_NORMALIZE);
  775.     glEndList();
  776. }
  777.  
  778. static void lights_init()
  779. {
  780.     int i;
  781.  
  782.     for (i = 0; i < nlights; i++)
  783.     {
  784.         glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, lights[i].diffuse);
  785.         glLightfv(GL_LIGHT0 + i, GL_SPECULAR, black.c);
  786.         glLightfv(GL_LIGHT0 + i, GL_AMBIENT, black.c);
  787.         glLightf(GL_LIGHT0 + i, GL_SPOT_EXPONENT, 4);
  788.         glLightf(GL_LIGHT0 + i, GL_SPOT_CUTOFF, 90);
  789.     }
  790.  
  791.     glLightfv(GL_LIGHT0 + nlights, GL_DIFFUSE, black.c);
  792.     glLightfv(GL_LIGHT0 + nlights, GL_SPECULAR, black.c);
  793.     glLightfv(GL_LIGHT0 + nlights, GL_AMBIENT, world_ambient.c);
  794.     glEnable(GL_LIGHT0 + nlights);
  795.  
  796.     /* GL_LIGHT0 + nlights + 1 willl eventually be used to draw the 
  797.     * refractions - stay tuned. */
  798.     glLightfv(GL_LIGHT0 + nlights + 1, GL_DIFFUSE, black.c);
  799.     glLightfv(GL_LIGHT0 + nlights + 1, GL_SPECULAR, black.c);
  800.     glLightfv(GL_LIGHT0 + nlights + 1, GL_AMBIENT, white.c);
  801. }
  802.  
  803. static int lights_move(int light, float dr, float dphi, float dtheta, int update)
  804. {
  805.     float cphi, sphi, x, y;
  806.     Point_b l, dl;
  807.  
  808.     if (!(dr || dphi || dtheta)) return 0;
  809.  
  810.     l = lights[light].pos - sphere_position;
  811.  
  812.     if (dr)
  813.     {
  814.         dl = l + l*dr;
  815.         if (dl.mag() > sphere_size) l = dl;
  816.     }
  817.  
  818.     if (dphi)
  819.     {
  820.         cphi = cos(dphi);
  821.         sphi = sin(dphi);
  822.         y = -l.pt[0]*sphi + l.pt[2]*cphi;
  823.  
  824.         /* This hack keeps with light from getting below the sphere - 
  825.         * the projection sections would completely freak if this ever
  826.         * happened  - sphere_size is multiplied by two as a fudge factor*/
  827.         if (y < 2.0*sphere_size)
  828.         {
  829.             dphi = atan2(l.pt[2] - 2.0*sphere_size, l.pt[0]);
  830.             cphi = cos(dphi);
  831.             sphi = sin(dphi);
  832.         }
  833.         
  834.         x = l.pt[0];
  835.         l.pt[0] = x*cphi + l.pt[2]*sphi;
  836.         l.pt[2] = -x*sphi + l.pt[2]*cphi;
  837.     }
  838.  
  839.     if (dtheta)
  840.     {
  841.         light_rotation[light] += degrees(dtheta);
  842.         light_rotation[light] = degrees_clamp(light_rotation[light]);
  843.     }
  844.  
  845.     lights[light].pos = l + sphere_position;
  846.     lights[light].pos.pt[3] = 1;
  847.  
  848.     lights_init_position(light);
  849.     lights_list_init(light);
  850.  
  851.     if (update) lights_move_update(light, dr ? 1 : 0, dphi ? 1 : 0, 
  852.     dtheta ? 1 : 0);
  853.     return 1;
  854. }
  855.  
  856. static void lights_move_update(int light, int dr, int dphi, int dtheta)
  857. {
  858.     if (dr)
  859.     {
  860.         disk_build(light);
  861.         shadow_refraction_full_build(light);
  862.         shadow_list_init(light);
  863.         refraction_list_init(light);  
  864.     }
  865.     else if (dphi)
  866.     {
  867.         shadow_refraction_full_build(light);
  868.         shadow_list_init(light);
  869.         refraction_list_init(light);
  870.     }
  871.     else if (dtheta)
  872.     {
  873.     }
  874.  
  875. }
  876.  
  877.  
  878. static int get_lists(int size)
  879. {
  880.     int i;
  881.     i = glGenLists(size);
  882.     
  883.     if (size && !i)
  884.     {
  885.         fprintf(stderr, "Unable to allocate %d display lists.\n");
  886.         exit(1);
  887.     }
  888.     
  889.     return i;
  890. }
  891.  
  892. static void lists_init()
  893. {
  894.     //list_square = get_lists(1);
  895.     lists_shadows = get_lists(nlights);
  896.     lists_refraction = get_lists(nlights);
  897.     lists_lights = get_lists(nlights);
  898.     list_sphere = get_lists(1);
  899.     list_spheredisk = get_lists(1);
  900.     list_lights_on = get_lists(1);
  901.     list_lights_off = get_lists(1);
  902.     list_light_draw = get_lists(1);
  903.  
  904.     // sphere_build();
  905. }
  906.  
  907. static inline int sphere_npoints() 
  908. {
  909.     return (spherediv+1)*spherediv*3;
  910. }
  911.  
  912. void sphere_build()
  913. {
  914.     int nspherepts;
  915.     int r, t, index;
  916.     float c, s;
  917.  
  918.     delete spherepts;
  919.     nspherepts = sphere_npoints();
  920.     if (nspherepts == 0) return;
  921.     spherepts = new GLfloat[nspherepts];
  922.  
  923.     index = 0;
  924.     for (r = 0; r <= spherediv; r++)
  925.     {
  926.         spherepts[index++] = sin(M_PI * (float)r / (float)spherediv);
  927.         spherepts[index++] = 0;
  928.         spherepts[index++] = -cos(M_PI * (float)r / (float)spherediv);
  929.     }
  930.     
  931.     for (t = 1; t < spherediv; t++)
  932.     {
  933.         c = cos(2.0 * M_PI * (float)t / (float)spherediv);
  934.         s = sin(2.0 * M_PI * (float)t / (float)spherediv);
  935.     
  936.         for (r = 0; r <= spherediv; r++)
  937.         {
  938.             spherepts[index++] = c*spherepts[r*3];
  939.             spherepts[index++] = s*spherepts[r*3];
  940.             spherepts[index++] = spherepts[r*3 + 2];
  941.         }
  942.     }
  943. }
  944.  
  945. void sphere_list_init()
  946. {
  947.     glNewList(list_sphere, GL_COMPILE);
  948.     sphere_disk.draw_by_perimeter();
  949.     glEndList();
  950. }  
  951.  
  952. void sphere_draw()
  953. {
  954.     int r, t, p1, p2;
  955.  
  956.     for (t = 1; t < spherediv; t++)
  957.     {
  958.         glBegin(GL_QUAD_STRIP);
  959.         p1 = (t - 1) * (spherediv + 1);
  960.         p2 = t * (spherediv + 1);
  961.         
  962.         for (r = 0; r <= spherediv; r++, p1++, p2++)
  963.         {
  964.             glNormal3fv(&spherepts[p1*3]);
  965.             glVertex3fv(&spherepts[p1*3]);
  966.             glNormal3fv(&spherepts[p2*3]);
  967.             glVertex3fv(&spherepts[p2*3]);
  968.         }
  969.         
  970.         glEnd();
  971.     }
  972.  
  973.     glBegin(GL_QUAD_STRIP);
  974.     p1 = (spherediv + 1) * (spherediv - 1);
  975.     p2 = 0;
  976.     
  977.     for (r = 0; r <= spherediv; r++, p1++, p2++)
  978.     {
  979.         glNormal3fv(&spherepts[p1*3]);
  980.         glVertex3fv(&spherepts[p1*3]);
  981.         glNormal3fv(&spherepts[p2*3]);
  982.         glVertex3fv(&spherepts[p2*3]);
  983.     }
  984.     glEnd();
  985. }
  986.  
  987. static void disk_build()
  988. {
  989.     int i;
  990.     for (i = 0; i < nlights; i++) disk_build(i);
  991. }
  992.  
  993. static void disk_build(int disk)
  994. {
  995.     Point_b light;
  996.     light = lights[disk].pos;
  997.  
  998.     disks[disk].free_points_normals();
  999.     disks[disk].free_colors();
  1000.  
  1001.     disks[disk].set_divisions(diskdiv, diskdiv);
  1002.     disks[disk].set_angle(2.0 * 
  1003.     acos(sphere_size / light.dist(sphere_position)));
  1004.     disks[disk].fill_points();
  1005. }
  1006.  
  1007. static void shadow_list_init()
  1008. {
  1009.     int i;
  1010.     for (i = 0; i < nlights; i++) shadow_list_init(i);
  1011. }
  1012.  
  1013. static void shadow_list_init(int n)
  1014. {
  1015.     Color c(square_ambient[0], square_ambient[1], square_ambient[2]);
  1016.  
  1017.     c *= world_ambient;
  1018.  
  1019.     glNewList(lists_shadows + n, GL_COMPILE);
  1020.     glColorMask(lights[n].shadow_mask[0], lights[n].shadow_mask[1],
  1021.     lights[n].shadow_mask[2], lights[n].shadow_mask[3]);
  1022.     glDisable(GL_DEPTH_TEST);
  1023.     glColor3fv(c.c);
  1024.     shadows[n].draw_by_perimeter(0, 0, 1);
  1025.     glColorMask(1, 1, 1, 1);
  1026.     glEndList();
  1027. }
  1028.  
  1029. static void refraction_list_init()
  1030. {
  1031.     int i;
  1032.     for (i = 0; i < nlights; i++) refraction_list_init(i);
  1033. }
  1034.  
  1035. static void refraction_list_init(int n)
  1036. {
  1037.     /* This could be loads simpler if it weren't for the texture mapping -
  1038.     * that's where all this weirdness with GL_LIGHT0 + nlights + 1 comes 
  1039.     * in */
  1040.     glNewList(lists_refraction + n, GL_COMPILE);
  1041.  
  1042.     glEnable(GL_LIGHTING);
  1043.     glCallList(list_lights_off);
  1044.     /* This is white ambient light */
  1045.     glEnable(GL_LIGHT0 + nlights + 1);
  1046.     glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, black.c);
  1047.     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black.c);
  1048.     glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
  1049.     glEnable(GL_COLOR_MATERIAL);
  1050.  
  1051.     glBlendFunc(GL_ONE, GL_ONE);
  1052.     glEnable(GL_BLEND);
  1053.  
  1054.     glDisable(GL_DEPTH_TEST);
  1055.     refraction[n].draw();
  1056.  
  1057.     glDisable(GL_BLEND);
  1058.  
  1059.     glDisable(GL_COLOR_MATERIAL);
  1060.     glDisable(GL_LIGHT0 + nlights + 1);
  1061.     glDisable(GL_LIGHTING);
  1062.  
  1063.     glEndList();
  1064. }
  1065.  
  1066. static void shadow_refraction_full_build()
  1067. {
  1068.     int i;
  1069.     for (i = 0; i < nlights; i++) shadow_refraction_full_build(i);
  1070. }
  1071.  
  1072. /* This entire function is written a bit oddly... */
  1073. static void shadow_refraction_full_build(int n)
  1074. {
  1075.     Color c;
  1076.     float dist_light;
  1077.     Point_b dlight, zaxis;
  1078.  
  1079.     /* Make sure that we're starting over from scratch */
  1080.     shadows[n].free_points_normals();
  1081.     shadows[n].free_colors();
  1082.     refraction[n].free_points_normals();
  1083.     refraction[n].free_colors();
  1084.  
  1085.     dlight = lights[n].pos - sphere_position;
  1086.     dist_light = dlight.mag();
  1087.     dlight.unitize();
  1088.     zaxis.pt[0] = 0;
  1089.     zaxis.pt[1] = 0;
  1090.     zaxis.pt[2] = 1;
  1091.  
  1092.     shadows[n].set_divisions(disks[n].get_rdivisions(), 
  1093.     disks[n].get_tdivisions());
  1094.     refraction[n].set_divisions(disks[n].get_rdivisions(), 
  1095.     disks[n].get_tdivisions());
  1096.  
  1097.     shadows[n].alloc_points();
  1098.     shadows[n].face_direction(dlight, disks[n]);
  1099.     shadows[n].scale_translate(sphere_size, sphere_position);
  1100.  
  1101.     c = square_diffuse;
  1102.     c *= lights[n].diffuse; 
  1103.  
  1104.     refraction[n].copy_points(disks[n]);
  1105.     refraction[n].set_colors(c);
  1106.     refraction[n].scale_colors_by_z();
  1107.  
  1108.     refraction[n].scale(sphere_size);
  1109.     refraction[n].refract_normals(zaxis * dist_light, index);
  1110.     refraction[n].face_direction(dlight);
  1111.  
  1112.     refraction[n].project_borrow_points(shadows[n]);  
  1113.     refraction[n].free_normals();
  1114.     shadows[n].project(lights[n].pos);
  1115.     if (index != 1.0) refraction[n].scale_colors_by_darea(shadows[n]);
  1116. }
  1117.  
  1118. int scene_load_texture(char *texfile)
  1119. {
  1120.     teximage = tkRGBImageLoad(texfile);
  1121.  
  1122.     if (teximage == NULL) return 0;
  1123.     else return 1;
  1124.  
  1125.     return 0;
  1126. }
  1127.  
  1128. void texture_init()
  1129. {
  1130.     if (teximage == NULL) return;
  1131.  
  1132.     gluBuild2DMipmaps(GL_TEXTURE_2D, 3, teximage->sizeX, teximage->sizeY,
  1133.     GL_RGB, GL_UNSIGNED_BYTE, (const void *) teximage->data);
  1134.  
  1135.     glMatrixMode(GL_TEXTURE);
  1136.     glLoadIdentity();
  1137.     glRotatef(90, 0, 0, 1);
  1138.  
  1139.     glTranslatef(.5, .5, 0);
  1140.     glScalef(.1, .1, 1);
  1141.     glMatrixMode(GL_MODELVIEW);
  1142.  
  1143.     //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 
  1144.     //GL_NEAREST_MIPMAP_NEAREST);
  1145.     //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
  1146.     //GL_LINEAR);
  1147.     
  1148.     /* New */
  1149.     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  1150.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  1151.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  1152. }
  1153.